package com.dc.datacollect.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dc.datacollect.components.upload.FileUploadService;
import com.dc.datacollect.conduit.R;
import com.dc.datacollect.constant.BaseConstant;
import com.dc.datacollect.constant.LoginCookieConstant;
import com.dc.datacollect.constant.VerificationCodeConstant;
import com.dc.datacollect.constant.type.UserType;
import com.dc.datacollect.dto.SysUserDTO;
import com.dc.datacollect.dto.input.AlterPasswordInput;
import com.dc.datacollect.dto.input.LoginInput;
import com.dc.datacollect.dto.input.RegisterInput;
import com.dc.datacollect.dto.input.UpdateUserInfoInput;
import com.dc.datacollect.dto.output.SysUserInfoOutput;
import com.dc.datacollect.entity.Collector;
import com.dc.datacollect.entity.User;
import com.dc.datacollect.helpers.EmailHelper;
import com.dc.datacollect.helpers.RememberMeHelper;
import com.dc.datacollect.helpers.VerificationCodeProvide;
import com.dc.datacollect.utils.CookieUtils;
import com.dc.datacollect.utils.DesUtils;
import com.dc.datacollect.utils.MD5Util;
import com.dc.datacollect.helpers.SessionProvide;
import com.dc.datacollect.utils.ReflectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.security.provider.MD5;

import java.util.Arrays;

@Service
public class IndexService {
    @Autowired
    private CollectorService collectorService;

    @Autowired
    private UserService userService;

    @Autowired
    private VerificationCodeProvide verificationCodeProvide;

    @Autowired
    private FileUploadService fileUploadService;



    public Boolean alterPassword(AlterPasswordInput alterPasswordInput) throws Exception {
        Short userType = SessionProvide.getLoginObject().getType();
        Long userId = SessionProvide.getLoginObject().getId();
        if (alterPasswordInput.getNewPassword().equals(alterPasswordInput.getOldPassword() )) {
            throw new Exception("新密码与旧密码不能相同！");
        }
        if (UserType.BASE_USER.equals(userType)) {
            // 普通用户
            // -- 查出用户
            User user = userService.getById(userId);
            if (user == null) {
                throw new Exception("用户不存在！");
            }
            // -- 判断输入的旧密码是否与系统密码相同
            if (! MD5Util.md5(alterPasswordInput.getOldPassword()).equals(user.getPassword()) ) {
                throw new Exception("输入的旧密码错误！");
            }
            // -- 修改密码
            user.setPassword(MD5Util.md5(alterPasswordInput.getNewPassword()));
            return userService.updateById(user);
        }else {
            // 收集者
            // -- 查出收集者
            Collector collector = collectorService.getById(userId);
            if (collector == null) {
                throw new Exception("用户不存在！");
            }
            // -- 判断输入的旧密码是否与系统密码相同
            if (! MD5Util.md5(alterPasswordInput.getOldPassword()).equals(collector.getPassword()) ) {
                throw new Exception("输入的旧密码错误！");
            }
            // -- 修改密码
            collector.setPassword(MD5Util.md5(alterPasswordInput.getNewPassword()));
            return collectorService.updateById(collector);

        }
    }

    public boolean sendCode(String email) {
        String verificationCode = verificationCodeProvide.genCode(email, VerificationCodeConstant.VERIFICATION_CODE_EFFECTIVE_TIME);
        try {
            new EmailHelper.Builder("注册验证码","您的验证码："+verificationCode+"，注意不要泄露给别人！")
                    .build().asyncSend(Arrays.asList(email));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public Boolean updateUserInfo(UpdateUserInfoInput updateUserInfoInput) throws Exception {
        SysUserDTO loginObject = SessionProvide.getLoginObject();
        Long SysUserId = loginObject.getId();
        // 上传文件
        MultipartFile avatarFile = updateUserInfoInput.getAvatarFile();
        String avatar = null;
        if (avatarFile != null) {
            avatar = fileUploadService.MultipartFileToUrl(avatarFile);
        }
        if (UserType.BASE_USER.equals(loginObject.getType())) {
            // 是普通用户
            // 查出用户
            User user = userService.getById(SysUserId);
            ReflectionUtils.copyProperties(updateUserInfoInput,user);
            if (avatar != null) {
                user.setAvatar(avatar);
            }
            userService.updateById(user);
        }else {
            // 是收集者
            Collector collector = collectorService.getById(SysUserId);
            ReflectionUtils.copyProperties(updateUserInfoInput,collector);
            if (avatar != null) {
                collector.setAvatar(avatar);
            }
            collectorService.updateById(collector);
        }
        return true;
    }

    public SysUserInfoOutput getUserInfo() throws Exception {
        SysUserDTO loginObject = SessionProvide.getLoginObject();
        Long sysUserId = loginObject.getId();
        Object sysUserObject = null;
        if (UserType.BASE_USER.equals(loginObject.getType())) {
            // 是普通用户
            sysUserObject = userService.getById(sysUserId);
        }else {
            // 是收集者
            sysUserObject =collectorService.getById(sysUserId);
        }
        if (sysUserObject == null) {
            throw new Exception("用户不存在！！");
        }
        SysUserInfoOutput sysUserInfoOutput = new SysUserInfoOutput();
        BeanUtils.copyProperties(sysUserObject,sysUserInfoOutput);
        return sysUserInfoOutput;
    }

    /**
     * 将用户信息放到Session中
     * @param obj
     * @param type
     * @throws Exception
     */
    private void loginHandle(Object obj,String password, Short type,Boolean rememberMe) throws Exception {
        // 传入的obj必须要有三个属性 type username password
        SysUserDTO sysUserDTO = new SysUserDTO();
        sysUserDTO.setType(type);
        ReflectionUtils.copyProperties(obj, sysUserDTO);
        if (StringUtils.isEmpty(sysUserDTO.getType()) || StringUtils.isEmpty(sysUserDTO.getUsername())) {
            throw new Exception("登录失败！");
        }
        if (StringUtils.isEmpty(sysUserDTO.getId()) ) {
            // 可能注册后登录的，需要查出id
            if (UserType.BASE_USER.equals(type)) {
                LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
                userQueryWrapper.eq(User::getUsername,sysUserDTO.getUsername());
                User user = userService.getOne(userQueryWrapper);
                if (user == null ) {
                    throw new Exception("登录异常，用户不存在！");
                }
                sysUserDTO.setId(user.getId());
            }else {
                LambdaQueryWrapper<Collector> collectorQueryWrapper = new LambdaQueryWrapper<>();
                collectorQueryWrapper.eq(Collector::getUsername,sysUserDTO.getUsername());
                Collector collector = collectorService.getOne(collectorQueryWrapper);
                if (collector == null ) {
                    throw new Exception("登录异常，用户不存在！");
                }
                sysUserDTO.setId(collector.getId());
            }
        }
        System.out.println("登录成功："+sysUserDTO);
        SessionProvide.set(BaseConstant.USER_SESSION_KEY, sysUserDTO);
        // 登录成功后，看是否记住我
        if (rememberMe) {
            RememberMeHelper.rememberMe(sysUserDTO.getUsername(),password);
        }
    }

    public Boolean login(LoginInput loginInput) throws Exception {
        String username = loginInput.getUsername();
        String password = loginInput.getPassword();
        Boolean rememberMe = loginInput.getRememberMe();
        // 先尝试User，如果没有找到再找收集者
        LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
        userQueryWrapper.eq(User::getUsername,username)
                .eq(User::getPassword, MD5Util.md5(password));
        User user = userService.getOne(userQueryWrapper);
        if (user != null) {
            // 使用用户登录成功
            loginHandle(user,user.getPassword(), UserType.BASE_USER,rememberMe);
            return true;
        }
        // 尝试收集者登录
        LambdaQueryWrapper<Collector> collectorQueryWrapper = new LambdaQueryWrapper<>();
        collectorQueryWrapper.eq(Collector::getUsername,username)
                .eq(Collector::getPassword,MD5Util.md5(password));
        Collector collector = collectorService.getOne(collectorQueryWrapper);
        if (collector == null) {
            throw new Exception("用户名或密码错误！");
        }
        loginHandle(collector,collector.getPassword(), UserType.COLLECTOR,rememberMe);
        return true;

    }

    public Boolean register(RegisterInput registerInput) throws Exception {
        // 检查验证码
        verificationCodeProvide.verifyCode(registerInput.getEmail(), registerInput.getCode());
        String md5Password = MD5Util.md5(registerInput.getPassword());
        if (UserType.BASE_USER.equals(registerInput.getType())) {
            // 注册为普通用户
            // 判断是否存在用户
            LambdaQueryWrapper<User> userQueryWrapperByUsername = new LambdaQueryWrapper<>();
            userQueryWrapperByUsername.eq(User::getUsername,registerInput.getUsername());
            User user = userService.getOne(userQueryWrapperByUsername);
            if (user != null ) {
                // 用户已经存在
                throw new Exception("用户已经存在！");
            }
            LambdaQueryWrapper<User> userQueryWrapperByEmail = new LambdaQueryWrapper<>();
            userQueryWrapperByEmail.eq(User::getEmail,registerInput.getEmail());
            user = userService.getOne(userQueryWrapperByEmail);
            if (user != null) {
                // 邮箱已经被绑定或用户重复注册
                throw new Exception("邮箱已经被绑定！绑定的用户名是"+user.getUsername());
            }
            User registerUser = new User();
            BeanUtils.copyProperties(registerInput,registerUser);
            // 密码需要加密
            registerUser.setPassword(md5Password);
            userService.save(registerUser);
            // 需要密文密码
            loginHandle(registerUser,md5Password, UserType.BASE_USER,true);
        }else {
            // 注册为收集者
            LambdaQueryWrapper<Collector> collectorQueryWrapperByUsername = new LambdaQueryWrapper<>();
            collectorQueryWrapperByUsername.eq(Collector::getUsername,registerInput.getUsername());
            Collector collector = collectorService.getOne(collectorQueryWrapperByUsername);
            if ( collector != null ) {
                // 已经注册
                throw new Exception("用户已经存在！");
            }
            LambdaQueryWrapper<Collector> collectorQueryWrapperByEmail = new LambdaQueryWrapper<>();
            collectorQueryWrapperByEmail.eq(Collector::getEmail,registerInput.getEmail());
            collector = collectorService.getOne(collectorQueryWrapperByEmail);
            if (collector != null) {
                // 邮箱已经被绑定或用户重复注册
                throw new Exception("邮箱已经被绑定！绑定的用户名是"+collector.getUsername());
            }
            Collector registerCollector = new Collector();
            BeanUtils.copyProperties(registerInput,registerCollector);
            registerCollector.setPassword(md5Password);
            collectorService.save(registerCollector);
            loginHandle(registerCollector,md5Password, UserType.COLLECTOR,true);
        }
        return true;
    }

    public Boolean tryRememberMeLogin() throws Exception {
        RememberMeHelper.Me me = RememberMeHelper.verifyLogin();
        if (me == null) {
            return false;
        }
        // 验证（如果用户修改了密码会验证失败）
        LambdaQueryWrapper<User> userLambdaWrapper = new LambdaQueryWrapper<>();
        userLambdaWrapper.eq(User::getUsername,me.getUsername());
        User user = userService.getOne(userLambdaWrapper);
        if (user != null) {
            boolean isDecryptSuccess = RememberMeHelper.decrypt(user.getUsername(), user.getPassword(), me.getMd5text());
            if (! isDecryptSuccess) {
                return false;
            }
            loginHandle(user,user.getPassword(),UserType.BASE_USER,true);
            return true;
        }
        // 尝试使用收集者记住我登录
        LambdaQueryWrapper<Collector> collectorQueryWrapper = new LambdaQueryWrapper<>();
        collectorQueryWrapper.eq(Collector::getUsername,me.getUsername());
        Collector collector = collectorService.getOne(collectorQueryWrapper);
        if (collector != null) {
            boolean isDecryptSuccess = RememberMeHelper.decrypt(collector.getUsername(), collector.getPassword(), me.getMd5text());
            if (isDecryptSuccess) {
                loginHandle(collector,collector.getPassword(),UserType.COLLECTOR,true);
                return true;
            }
        }
        return false;
    }
}
